package com.dream.service.recommender.hub.rec;

import com.dream.common.model.response.BaseResponse;
import com.dream.common.model.response.ErrorCode;
import com.dream.service.recommender.hub.util.CacheUtil;
import com.dream.service.recommender.hub.util.ParamUtil;
import com.dream.service.recommender.toolkits.cache.RedisCache;
import com.dream.service.recommender.toolkits.utils.ConfigUtil;
import com.dream.service.recommender.toolkits.utils.StringUtils;
import com.dream.service.search.api.SearchRecallService;
import com.dream.service.search.domain.entity.ShopifyProductRecallResult;
import com.dream.service.search.domain.request.ShopifyProductSearchRequest;
import com.dream.service.recommender.base.compare.WeightComparator;
import com.dream.service.recommender.base.impl.BaseRecommenderService;
import com.dream.service.recommender.domain.model.UserInfo;
import com.dream.service.recommender.domain.request.BaseRequest;
import com.dream.service.recommender.domain.request.FrontParam;
import com.dream.service.recommender.domain.response.RecommenderData;
import com.dream.service.recommender.domain.response.RecommenderItem;
import com.dream.service.recommender.domain.response.RecommenderShopifyProduct;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * P.C. 坑位推荐
 * Created by zhiji on 2016/05/14.
 */
public class PPCRandEnterRecommender extends BaseRecommenderService {

    private SearchRecallService searchRecallService;

    public SearchRecallService getSearchRecallService() {
        return searchRecallService;
    }

    @Autowired
    public void setSearchRecallService(SearchRecallService searchRecallService) {
        this.searchRecallService = searchRecallService;
    }

    // 获取商品数据倍数
    private int multiple = 40;

    // 失效时间间隔 (sec)
    private int residue_time_interval = 5 * 60;

    // 缓存
    private final String cacheKey = "rec_ppc_randenter_";

    // 缓存
    private RedisCache redisCache = RedisCache.getInstance();

    @Override
    public BaseResponse<RecommenderData> getRecommender(BaseRequest<FrontParam> frontParamBaseRequest) {
        long sTime = System.currentTimeMillis();
        BaseResponse<RecommenderData> recommenderResponse = new BaseResponse<RecommenderData>();
        try {
            if (frontParamBaseRequest == null || frontParamBaseRequest.getParam() == null || frontParamBaseRequest.getParam().getUser() == null) {
                return buildResult(recommenderResponse, false, ErrorCode.PARAM_ERROR.getCode(), ErrorCode.PARAM_ERROR.getError_msg(), null);
            }
            FrontParam frontParam = frontParamBaseRequest.getParam();
            int pagesize = ParamUtil.getPageSize(frontParam);
            int page = ParamUtil.getPage(frontParam);
           /* int skip = pagesize * (page - 1);*/
            String pin = ParamUtil.getPin(frontParam);
            String uuid = ParamUtil.getUUid(frontParam);
            // 获取已经展示的Key
            Set<Long> existKeys = gatherExistKeys(pin, uuid, page, pagesize);

            List<ShopifyProductRecallResult> recallResults = gatherSearchRecallData(pagesize * multiple, existKeys, 0);

            RecommenderData recommenderData = buildResult(recallResults);

            recommenderResponse = buildResult(recommenderResponse, true, ErrorCode.OK.getCode(), "", recommenderData, 0, pagesize);
            Set<Long> keys = rebuildPositionInfo(recommenderResponse.getResult());
            // 封装跳转链接
            packageSkipUrl(recommenderResponse.getResult().getList(), frontParam, keys);
            backupExistKeys(pin, uuid, keys);
            long usedTime = System.currentTimeMillis() - sTime;
            recommenderData.setLatency(usedTime);
            recommenderResponse.setLatency(usedTime);
            return recommenderResponse;
        } catch (Exception e) {
            e.printStackTrace();
            return buildResult(recommenderResponse, false, ErrorCode.PROCESS_ERROR.getCode(), e.getMessage(), null);
        }
    }

    /**
     * 更新位置信息
     * @param recommenderData
     * @return
     */
    public Set<Long> rebuildPositionInfo(RecommenderData recommenderData) {
        if (recommenderData == null || StringUtils.isEmpty(recommenderData.getList())) {
            return null;
        }
        List<RecommenderItem> items = recommenderData.getList();
        Set<Long> keys = new HashSet<Long>();
        int pos = 1;
        for (RecommenderItem recommenderItem : items) {
            recommenderItem.setPos(pos++);
            if (recommenderItem instanceof RecommenderShopifyProduct) {
                try {
                    keys.add(((RecommenderShopifyProduct) recommenderItem).getProduct_id());
                } catch (Exception e) {}
            }
        }
        return keys;
    }

    /**
     * 获取已存在的Keys
     * @param pin
     * @param uuid
     * @param pageNum
     * @param pageSize
     * @return
     */
    public Set<Long> gatherExistKeys(String pin, String uuid, int pageNum, int pageSize) {
        if (StringUtils.isEmpty(pin) && StringUtils.isEmpty(uuid)) {
            return Collections.emptySet();
        }
        String major_uid = StringUtils.isEmpty(pin) ? uuid : pin;
        String key = cacheKey.concat("_").concat(major_uid);
        if (pageNum == 1) {
            redisCache.delKey(key.getBytes());
            return Collections.emptySet();
        }
        Set<Long> keys = CacheUtil.getExistSpus(redisCache, key, (pageNum - 1) * pageSize);
        if (keys == null) {
            return Collections.emptySet();
        }
        return keys;
    }

    private List<ShopifyProductRecallResult> gatherSearchRecallData(int limit, Set<Long> existKeys, int skip) {
        ShopifyProductSearchRequest request = new ShopifyProductSearchRequest();
        request.setLimit(limit);
        request.setSkip(skip);
        if (existKeys != null && !existKeys.isEmpty()) {
            request.setExistKeys(existKeys);
        }
        try {
            if (searchRecallService == null) {
                return null;
            }
            BaseResponse<List<ShopifyProductRecallResult>> recallResponse = searchRecallService.shopifyProductSearchRecall(request);
            if (recallResponse.isSuccess()) {
                return recallResponse.getResult();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void backupExistKeys(String pin, String uuid, Set<Long> keys) {
        if (StringUtils.isEmpty(pin) && StringUtils.isEmpty(uuid)) return;
        String major_uid = StringUtils.isEmpty(pin) ? uuid : pin;
        String key = cacheKey.concat("_").concat(major_uid);
        CacheUtil.backupCache(redisCache, key, keys, residue_time_interval, -1);
    }

    /**
     * 封装结果
     * @param recallResults
     * @return
     */
    private RecommenderData buildResult(List<ShopifyProductRecallResult> recallResults) {
        if (StringUtils.isEmpty(recallResults)) {
            return new RecommenderData();
        }
        RecommenderData<RecommenderShopifyProduct> recommenderData = new RecommenderData<RecommenderShopifyProduct>();
        List<RecommenderShopifyProduct> recommenderShopifyProducts = new ArrayList<RecommenderShopifyProduct>();
        recommenderData.setList(recommenderShopifyProducts);
        for (ShopifyProductRecallResult recallResult : recallResults) {
            RecommenderShopifyProduct recommenderShopifyProduct = buildProduct(recallResult);
            if (recommenderShopifyProduct != null) {
                recommenderShopifyProducts.add(recommenderShopifyProduct);
            }
        }
        SortAndRankByRand(recommenderData);// 排序
        return recommenderData;
    }

    /**
     * 封装商品信息
     * @param recallResult
     * @return
     */
    private RecommenderShopifyProduct buildProduct(ShopifyProductRecallResult recallResult) {
        if (recallResult == null) {
            return null;
        }
        RecommenderShopifyProduct recommenderShopifyProduct = new RecommenderShopifyProduct();

        recommenderShopifyProduct.setTitle(recallResult.getTitle());
        recommenderShopifyProduct.setImage_url(recallResult.getImage_url());
        recommenderShopifyProduct.setProduct_id(recallResult.getProduct_id());
        recommenderShopifyProduct.setPrice(recallResult.getPrice());
        recommenderShopifyProduct.setOrig_price(recallResult.getOrig_price());
        recommenderShopifyProduct.setProduct_type(recallResult.getProduct_type());//需要添加这里 跟motif的不同
        if (!StringUtils.isEmpty(recallResult.getDisplay())) {
            recommenderShopifyProduct.setDisplay(recallResult.getDisplay());
        }
        /*recommenderShopifyProduct.setPromotion_remain_time();*/
        return recommenderShopifyProduct;
    }

    /**
     * 封装跳转链接
     * @param param
     * @param keys
     * @return
     */
    private void packageSkipUrl(List<RecommenderShopifyProduct> recommenderItems, FrontParam param, Set<Long> keys) {
        if (keys == null || keys.isEmpty()) {
            return ;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(ConfigUtil.getPro("openapi_prefix"));
        builder.append("recid=200001&pagenum=1&pagesize=48"); // 固定推荐位 - 固定页码、页面展示商品数（48）
        UserInfo user = param.getUser();
        if (user != null) {
            builder.append("&pin=").append(user.getPin() == null ? "" : user.getPin());
            builder.append("&uuid=").append(user.getUuid() == null ? "" : user.getUuid());
        }
        builder.append("&spus=").append(setToString(keys));
        String extra = param.getExtra_info();
        if (!StringUtils.isEmpty(extra)) {
            builder.append("&extra=").append(extra);
        }

        Map<String, String> extraKVs = param.getExtra_values();
        if (extraKVs != null && !extraKVs.isEmpty()) {
            builder.append("&extra=").append(packageExtractKV(extraKVs));
        }

        String os = param.getOs();
        if (!StringUtils.isEmpty(os)) {
            builder.append("&os=").append(os);
        }
        String version = param.getVersion();
        if (!StringUtils.isEmpty(version)) {
            builder.append("&ver=").append(version);
        }
        builder.append("&encode=UTF-8");
        String skip_url = builder.toString();

        for (RecommenderShopifyProduct item : recommenderItems) {
            item.setSkip_url(skip_url);
        }
    }

    private String packageExtractKV(Map<String, String> extraKVs) {
        StringBuilder builder = new StringBuilder();
        int pos = 0;
        for (String key : extraKVs.keySet()) {
            String value = extraKVs.get(key);
            if (pos == 0) {
                builder.append(key).append("=").append(value);
            } else {
                builder.append("\\$").append(key).append("=").append(value);
            }
            pos ++;
        }
        return builder.toString();
    }

    private String setToString(Set<Long> keys) {
        if (keys == null || keys.isEmpty()) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        int pos = 0;
        for (Long key : keys) {
            if (pos > 0) {
                builder.append(",").append(key);
            } else {
                builder.append(key);
            }
            pos ++;
        }
        return builder.toString();
    }

    public RecommenderData SortAndRankByRand(RecommenderData shopifyRecommenderData) {

        if (shopifyRecommenderData == null) {
            return shopifyRecommenderData;
        }

        List<RecommenderShopifyProduct> recommenderShopifyProducts = shopifyRecommenderData.getList();
        if (StringUtils.isEmpty(recommenderShopifyProducts)) {
            return shopifyRecommenderData;
        }

        Map<String, List<RecommenderShopifyProduct>> categoryItems = new HashMap<String, List<RecommenderShopifyProduct>>();
        for (RecommenderShopifyProduct recommenderShopifyProduct : recommenderShopifyProducts) {//根据cid重组spu
//            long spu = recommenderShopifyProduct.getSpu();
//            SPUData spuData = spuDataMap.get(spu);
//            if (spuData == null) {//是不是多余的判断
//                continue;
//            }
//            SpuBase spuBase = spuData.getSpuBase();
            List<RecommenderShopifyProduct> relSkus = categoryItems.get(recommenderShopifyProduct.getProduct_type());
//            System.out.println(recommenderShopifyProduct.getProduct_type());
            if (relSkus == null) {
                relSkus = new ArrayList<RecommenderShopifyProduct>();
                categoryItems.put(recommenderShopifyProduct.getProduct_type(), relSkus);
            }
            relSkus.add(recommenderShopifyProduct);

        }
        List<RecommenderShopifyProduct> sortRecommenderItems = new ArrayList<RecommenderShopifyProduct>();
        boolean loop = true;
        do {
//            System.out.println(1);

//            Map<Integer,Integer> cidSizeMap = new HashMap<Integer,Integer>();//cid是Int，可能跟表里存的不同
            Iterator<Map.Entry<String, List<RecommenderShopifyProduct>>> entryiterator = categoryItems.entrySet().iterator();
            List<RecommenderShopifyProduct> subRecommenderItems = new ArrayList<RecommenderShopifyProduct>(categoryItems.size());

            while (entryiterator.hasNext()) {
//                System.out.println(categoryItems.size());
                Map.Entry<String, List<RecommenderShopifyProduct>> productentry = entryiterator.next();
//                if(cidSizeMap.get(productentry.getKey())==null && !StringUtils.isEmpty(productentry.getValue())) {//得到每个cid下面有多少个商品,前提是cid下有商品
//                    cidSizeMap.put(productentry.getKey(),productentry.getValue().size());
//                }

//                int c_num=categoryItems.size();//cid个数
                int s_num = 2;//几个作为一次单次展示

                List<RecommenderShopifyProduct> productList = productentry.getValue();
                if (StringUtils.isEmpty(productList)) {
                    entryiterator.remove();
                    continue;
                }

                //int real_num = productentry.getValue().size() > s_num ? s_num : productentry.getValue().size();//根据实际剩余情况推到subRec中
                //for (int s_i = 0; s_i < real_num; s_i++) {
                RecommenderShopifyProduct recommenderSku = productList.remove(0);
                //    System.out.println(recommenderSku.getProduct_id());
                subRecommenderItems.add(recommenderSku);
                //}
                recommenderSku.setW(Math.random());
//                System.out.println(recommenderSku.getProduct_id()+":"+recommenderSku.getW());
            }

            sortRecommenderItems.addAll(subRecommenderItems);
            if (categoryItems.isEmpty()) {
                loop = false;
            }
            if (categoryItems.size() == 1) {
                Set<String> keys = categoryItems.keySet();
                Iterator<String> keyiterator = keys.iterator();
                while (keyiterator.hasNext()) {
                    String catid = keyiterator.next();
                    sortRecommenderItems.addAll(categoryItems.get(catid));
                }
                loop = false;
            }
        } while (loop);

        Collections.sort(sortRecommenderItems, new WeightComparator());
        shopifyRecommenderData.setList(sortRecommenderItems);
        return shopifyRecommenderData;
    }

}
